local BaseLayer = requireLayerUI("BaseLayer")
local wxCalculateLayer = class("wxCalculateLayer", BaseLayer)

local QuickCell = requireUtil("QuickCell")
require("stab.scripts.init.wxUtil")

local ONETIME = 1 
local ALLTIME = 2
local CALCOUNT = 3

local IGNOREFILE = {
    "sceneTree",
    "wxFrame",
    "wxNodePanel",
    "wxMenu",
    "wxUtil",
    "wxTree",
    "wxCalculateLayer",
}


function wxCalculateLayer:ctor()
    wxCalculateLayer.super.ctor(self)
end

function wxCalculateLayer.create(...)
    local layer = wxCalculateLayer.new()
    layer:Init(...)
    return layer
end

function wxCalculateLayer:Init(data)
    self._root = wxCreateExport("stab/scripts/init/LogFile.lua")
    self:addChild(self._root)
    self.ui = ui_delegate(self._root)
    self.listCell = {}
    self:InitData()
    self:InitEvent()   
    self.scheduleID = schedule(self,handler(self,self.Tick),1)
    self.autoFresh = true
    self.minCount = 0 
    self.minTime = 0 
    self.minAvTime = 0 
    self.funcName = ""
    return true
end

function wxCalculateLayer:InitEvent()
    self.sortType = ALLTIME
    self.ui.Button_close:addClickEventListener(function()    
        self:EndCalculate()    
        self:removeFromParent()
    end)
    self.ui.Button_hide:addClickEventListener(function()        
        self.ui.Panel_3:setVisible(not self.ui.Panel_3:isVisible())
    end)
    self.ui.Button_reset:addClickEventListener(function()        
        self:InitData()
    end)
    self.ui.Button_start:addClickEventListener(function()        
        self:BeginCalculate()
    end)
    self.ui.Button_stop:addClickEventListener(function()        
        self:EndCalculate()
    end)
    self.ui.Button_fresh:addClickEventListener(function()
        self.needFresh = true
    end)

    self.ui.CheckBox_Fresh:setSelected(self.autoFresh)
    self.ui.CheckBox_Fresh:addEventListener(function()
        self.autoFresh = self.ui.CheckBox_Fresh:isSelected()
    end)
    
    self.ui.TextField_Count:setString(self.minCount)
    self.ui.TextField_Count:addEventListener(function()
        self.minCount = tonumber(self.ui.TextField_Count:getString() or 0) or 0
    end)
    self.ui.TextField_AvTime:setString(self.minAvTime)
    self.ui.TextField_AvTime:addEventListener(function()
        self.minAvTime = tonumber(self.ui.TextField_AvTime:getString() or 0) or 0
    end)
    self.ui.TextField_TotalTime:setString(self.minTime)
    self.ui.TextField_TotalTime:addEventListener(function()
        self.minTime = tonumber(self.ui.TextField_TotalTime:getString() or 0) or 0 
    end)

    self.ui.TextField_FuncName:setString("")
    self.ui.TextField_FuncName:addEventListener(function()
        self.funcName = self.ui.TextField_FuncName:getString()
    end)

    local title = self.ui.Panel_Model
    self.title = {}
    self.title[CALCOUNT] = title:getChildByName("Text_Count")
    self.title[ONETIME] = title:getChildByName("Text_AvTime")
    self.title[ALLTIME] = title:getChildByName("Text_Time")
    for i , cell in pairs(self.title) do
        cell:addClickEventListener(function()   
            self.sortType = i   
            self:UpdateChoose() 
        end)
    end
    self:UpdateChoose()
end

function wxCalculateLayer:Tick()
    if self.ui.Panel_3:isVisible() and  (self.autoFresh or self.needFresh)  then 
        self.needFresh = false
        self:SortInfo(self.sortType)
        self:UpdateList()
    end
end

function wxCalculateLayer:UpdateChoose()
    for i, cell in pairs(self.title) do
       SET_COLOR_STYLE(cell, (i == self.sortType) and 1010 or 1009)
    end
end

function wxCalculateLayer:UpdateList()
    local count = table.nums(self.listCell)
    local infoCount = table.nums(self.ts)    
    if count > infoCount then
        for i = infoCount + 1, count do
            self.listCell[i]:removeFromParent()
            self.listCell[i] = nil
        end
    else
        for i = count + 1, infoCount do
            self.listCell[i] = self:CreateCell(i)
            self.ui.ListView_1:pushBackCustomItem(self.listCell[i])
        end
    end    
    for i = 1, infoCount do
        self:UpdateCell(self.listCell[i]:getChildByName("cell"), i)       
    end
end

function wxCalculateLayer:UpdateCell(cell, index)
    local info = self.ts[index] or {}
    if cell and not tolua.isnull(cell) then
        cell:getChildByName("Text_Name"):setString(info.source.."["..info.func.."]")
        cell:getChildByName("Text_Time"):setString(string.format("%10f",info.time))
        cell:getChildByName("Text_AvTime"):setString(string.format("%10f",info.dt))
        cell:getChildByName("Text_Count"):setString(info.count)
    end
end

function wxCalculateLayer:CreateCell(index)
    local size = self.ui.Panel_ModelEx:getContentSize()
    local cell_data = {}
    cell_data.size = size
    cell_data.wid = size.width
    cell_data.hei = size.height        
    cell_data.createCell = function()
        local cell = self.ui.Panel_ModelEx:cloneEx()
        cell:setVisible(true)
        cell:setName("cell")
        cell:getChildByName("Text_Name"):addClickEventListener(function()
            local info = self.ts[index]
            if info then
                local name_to_find = wxGetFileNameByPath(info.source)
                local fullPath = wxFindPathByFileName(name_to_find)
                local code = "code " .. fullPath      
                os.execute(code)
            end
        end)
        self:UpdateCell(cell, index)
        return cell
    end
    return QuickCell:Create(cell_data)
end

function wxCalculateLayer:SortInfo(sortType)

    self.ts = {}
    local dt = nil
    local count = nil  

    for k1, v1 in pairs(global.function_times) do
        if not self:IsIgnoreFile(k1) then
            for k, v in pairs(v1) do       
                if not self.funcName or self.funcName=="" or self.funcName== k then 
                    count = global.function_counts[k1][k]
                    dt = v / count
                    if self.minAvTime<= dt and  self.minTime <= v and self.minCount <= count then
                        table.insert(self.ts, {func = k, time = v, source = k1,count = count, dt = dt})           
                    end
                end
            end
        end
    end
    table.sort(self.ts,function(a , b )
        if sortType == ALLTIME then
            return a.time > b.time
        elseif sortType == ONETIME then
            return a.dt > b.dt
        elseif sortType == CALCOUNT then            
            return a.count > b.count
        end
    end)
end

function wxCalculateLayer:PrintLog(data)
    print(string.format("%-90s , allTime =%-20s , avTime = %-20s , callCount = %-6s ",data.name ,data.time ,data.dt ,data.count))
end

function wxCalculateLayer:hook_function(event, line)
    local info = debug.getinfo(2, "nS")    
    if not info.name then 
        return 
    end
    local t = socket.gettime()
    --if info.what == "Lua" then
        if event == "call" then
            -- 记录函数调用的时间
            global.function_timesBegin[info.source] = global.function_timesBegin[info.source] or {}
            global.function_timesBegin[info.source][info.name] = global.function_timesBegin[info.source][info.name] or {}
            table.insert(global.function_timesBegin[info.source][info.name] ,t)
        elseif event == "return" then
            -- 计算函数执行时间
            local count = 0 
            if global.function_timesBegin[info.source] and global.function_timesBegin[info.source][info.name] then 
                global.function_timesBegin[info.source][info.name][count] = nil
                count = #global.function_timesBegin[info.source][info.name]
            end
            if count >0 then 
                global.function_counts[info.source] = global.function_counts[info.source] or {}
                global.function_counts[info.source][info.name] = (global.function_counts[info.source][info.name] or 0) + 1
                global.function_times[info.source] = global.function_times[info.source] or {}
                global.function_times[info.source][info.name] = (global.function_times[info.source][info.name] or 0 ) +  t - global.function_timesBegin[info.source][info.name][count]
                global.function_timesBegin[info.source][info.name][count] =nil
     
            end
        end
    --end
end

function wxCalculateLayer:IsIgnoreFile(fileName)
    for i , file in pairs(IGNOREFILE) do
        if string.find(fileName, file) then
            return true
        end
    end
    return false
end

function wxCalculateLayer:InitData()
    global = global or {}
    global.function_times =  {}
    global.function_timesBegin =  {}
    global.function_counts = {}
end

function wxCalculateLayer:BeginCalculate()     
    debug.sethook(handler(self,self.hook_function), "cr")
end

function wxCalculateLayer:EndCalculate()
    debug.sethook()
end

return wxCalculateLayer
